use once_cell::sync::Lazy;
use std::collections::HashMap;

use crate::types::types::{BezierCurve, TransitionCurveSegment};

pub static mut CURVE_ARRAY_MAP: Lazy<HashMap<String, Vec<TransitionCurveSegment>>> =
    Lazy::new(|| HashMap::new());

// 获取贝塞尔曲线
// transition_curve的长度必须> 1
// t: 当前帧
fn get_bezier_curve_by_t(transition_curve: &[TransitionCurveSegment], t: f64) -> BezierCurve {
    let curve_num = transition_curve.len();
    assert!(curve_num > 1);
    let last_index = curve_num - 1;

    let mut begin: TransitionCurveSegment = Default::default();
    let mut end: TransitionCurveSegment = Default::default();
    for i in 0..curve_num {
        if i == last_index {
            continue;
        }

        let segment = transition_curve[i];
        begin = segment;
        end = transition_curve[i + 1];
        let current_main_point_x = match begin {
            TransitionCurveSegment::OnePoint(p) => p.0,
            TransitionCurveSegment::ThreePoints(ps) => ps.0 .0,
        };
        let next_main_point_x = match end {
            TransitionCurveSegment::OnePoint(p) => p.0,
            TransitionCurveSegment::ThreePoints(ps) => ps.0 .0,
        };
        if t >= current_main_point_x && t < next_main_point_x {
            break;
        }
    }

    let (p0, p1) = match begin {
        TransitionCurveSegment::OnePoint(p) => (p, p),
        TransitionCurveSegment::ThreePoints(p) => (p.0, p.2),
    };
    let (p2, p3) = match end {
        TransitionCurveSegment::OnePoint(p) => (p, p),
        TransitionCurveSegment::ThreePoints(ps) => (ps.1, ps.0),
    };
    (p0, p1, p2, p3)
}

// 得到相对于t的贝塞尔曲线
// t: 当前帧
fn get_bezier_curve_relative_t(bezier_curve: BezierCurve, t: f64) -> f64 {
    let re_begin_x = bezier_curve.0 .0;
    let re_end_x = bezier_curve.3 .0;
    let x_minus = re_end_x - re_begin_x;
    let t_minus = t - re_begin_x;
    t_minus / x_minus
}

// 获取贝塞尔曲线t的进度
fn get_bezier_curve_t_progress(bezier_curve: BezierCurve, t: f64) -> f64 {
    let ((.., p0), (.., p1), (.., p2), (.., p3)) = bezier_curve;
    let t_minus = 1. - t;
    let result1 = p0 * t_minus.powi(3);
    let result2 = 3. * p1 * t * t_minus.powi(2);
    let result3 = 3. * p2 * t.powi(2) * t_minus;
    let result4 = p3 * t.powi(3);
    1. - (result1 + result2 + result3 + result4)
}

// 获取t时刻的帧进度
fn get_frame_progress_by_t(transition_curve: &[TransitionCurveSegment], t: f64) -> f64 {
    let bezier_curve = get_bezier_curve_by_t(transition_curve, t);
    let relative_t = get_bezier_curve_relative_t(bezier_curve, t);
    get_bezier_curve_t_progress(bezier_curve, relative_t)
}

// 获取帧率进度
pub fn get_frame_state_progress_by_curve_string(curve: &str, frame_num: f64) -> Vec<f64> {
    let target_curve = unsafe { CURVE_ARRAY_MAP.get(curve) };
    assert!(target_curve.is_some());
    let target_curve = target_curve.unwrap();
    let t_gap = 1. / (frame_num - 1.);
    (0..frame_num as usize)
        .enumerate()
        .map(|(i, _)| i as f64 * t_gap)
        .map(|t| get_frame_progress_by_t(target_curve, t))
        .collect::<Vec<_>>()
}

pub fn get_frame_state_progress_by_curve_transition(
    curve: &[TransitionCurveSegment],
    frame_num: f64,
) -> Vec<f64> {
    let t_gap = 1. / (frame_num - 1.);
    (0..frame_num as usize)
        .enumerate()
        .map(|(i, _)| i as f64 * t_gap)
        .map(|t| get_frame_progress_by_t(curve, t))
        .collect::<Vec<_>>()
}

pub fn extend_curve_array_map(name: String, transition_curve: Vec<TransitionCurveSegment>) {
    unsafe {
        CURVE_ARRAY_MAP.insert(name, transition_curve);
    }
}
